using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using Decav.Gatsb.Configuration;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;

namespace Decav.Gatsb.Web
{
    /// <summary>
    /// Retrieves and resizes images that have been uploaded by users.
    /// </summary>
    public class UserImageHttpHandler : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            // First try to find the cached image.
            if (File.Exists(LocalPath))
            {
                context.Response.TransmitFile(LocalPath);
                return;
            }

            // If the file was not there, make sure the original is there
            // so we can use that one.
            if (!File.Exists(OriginalImageLocalPath))
            {
                context.Response.StatusCode = 404;
                context.Response.StatusDescription = "The image with that ID does not exist on the server.";
                return;
            }

            // Create a new image file for the size information from the original.
            CreateCachedImage();

            if (File.Exists(LocalPath))
            {
                context.Response.TransmitFile(LocalPath);
                return;
            }
        }

        private void CreateCachedImage()
        {
            using (Image original = Bitmap.FromFile(OriginalImageLocalPath))
            {
                Size targetSize = FindBestFitSize(original.Size);

                using (Bitmap target = new Bitmap(targetSize.Width, targetSize.Height))
                using (Graphics targetGfx = Graphics.FromImage(target))
                {
                    targetGfx.DrawImage(original,
                        new Rectangle(0, 0, targetSize.Width, targetSize.Height));

                    // Note there could be a race condition here if two requests are made
                    // for the same image at the same time.
                    target.Save(LocalPath, ImageFormat.Jpeg);
                }
            }
        }

        private Size FindBestFitSize(Size imageSize)
        {
            Size frameSize = Size;

            // Get the ratio that will give us a good fit into the frame.
            decimal widthRatio = (decimal)frameSize.Width / (decimal)imageSize.Width;
            decimal heightRatio = (decimal)frameSize.Height / (decimal)imageSize.Height;
            decimal usedRatio = Math.Min(widthRatio, heightRatio);

            if (usedRatio > 1.0M)
                return imageSize;

            return new Size(
                (int)(usedRatio * imageSize.Width),
                (int)(usedRatio * imageSize.Height));
        }

        /// <summary>
        /// Gets the local path to the file (where it is on disk).
        /// </summary>
        public string LocalPath
        {
            get
            {
                return Path.Combine(
                    GatsbConfigurationSection.Current.CachedUserUploadedImagesFolder,
                    FileName);
            }
        }

        /// <summary>
        /// Gets the name of the file being requested.
        /// </summary>
        public string FileName
        {
            get
            {
                Uri url = HttpContext.Current.Request.Url;
                string path = url.PathAndQuery.Split('?')[0];
                string fileName = Path.GetFileName(path);
                return fileName;
            }
        }

        /// <summary>
        /// Gets the file name of the original image, before it was resized.
        /// </summary>
        public string OriginalImageFileName
        {
            get
            {
                string fileName = FileName;
                return Path.GetFileNameWithoutExtension(fileName.Substring(3, fileName.Length - 3));
            }
        }

        /// <summary>
        /// Gets the path to the original image.
        /// </summary>
        public string OriginalImageLocalPath
        {
            get
            {
                return Path.Combine(
                    GatsbConfigurationSection.Current.UserUploadedImagesFolder,
                    OriginalImageFileName);
            }
        }

        /// <summary>
        /// Gets the size of the image to return.
        /// </summary>
        public UserImageSize SizeFlag
        {
            get
            {
                string size = FileName.Substring(0, 2);
                switch (size.ToLower())
                {
                    case "th":
                        return UserImageSize.Thumbnail;

                    case "md":
                        return UserImageSize.Medium;

                    case "lg":
                        return UserImageSize.Large;

                    case "or":
                    default:
                        return UserImageSize.Original;
                }
            }
        }

        /// <summary>
        /// Gets the length and width of the image in pixels.
        /// </summary>
        public Size Size
        {
            get
            {
                switch (SizeFlag)
                {
                    case UserImageSize.Large:
                        return new Size(400, 400);

                    case UserImageSize.Medium:
                        return new Size(220, 220);

                    case UserImageSize.Original:
                        return new Size(600, 600);

                    case UserImageSize.Thumbnail:
                        return new Size(120, 120);

                    default:
                        throw new NotImplementedException();
                }
            }

        }

        #endregion
    }
}
